mod state;
pub mod state_cache;
mod timeline;

use std::sync::Arc;

use redb::{TableDefinition, TableError};
use ruma::{events::AnyStrippedStateEvent, serde::Raw, OwnedRoomId, RoomId, UserId};

use crate::{Error, DATABASE};

pub struct Service {
    pub state: Arc<state::Service>,
    pub timeline: Arc<timeline::Service>,
    pub state_cache: Arc<state_cache::Service>,
}

const USERID_INVITESTATE: TableDefinition<&str, Vec<(String, Vec<u8>)>> =
    TableDefinition::new("user_invite_state");

impl Service {
    pub fn build() -> Self {
        Self {
            state: state::SERVICE.clone(),
            timeline: timeline::SERVICE.clone(),
            state_cache: state_cache::SERVICE.clone(),
        }
    }

    pub fn invited_rooms(
        &self,
        user_id: &UserId,
    ) -> Result<Vec<(OwnedRoomId, Vec<Raw<AnyStrippedStateEvent>>)>, Error> {
        let db = &DATABASE;
        let read_ctx = db.begin_read().map_err(redb::Error::from)?;
        let userid_invite_state = match read_ctx.open_table(USERID_INVITESTATE) {
            Err(TableError::TableDoesNotExist(_)) => {
                return Ok(vec![]);
            }
            res => res,
        }
        .map_err(redb::Error::from)?;
        let res = userid_invite_state
            .get(&user_id.as_str())
            .map_err(redb::Error::from)?;
        let res = res.map(|x| x.value()).unwrap_or_default();
        Ok(res
            .iter()
            .map(|(roomid, state)| {
                (
                    RoomId::parse(roomid).unwrap(),
                    serde_json::from_slice(&state).expect("Invalid invite state"),
                )
            })
            .collect())
    }
}
